perm filename XERROR.MSS[WHT,LSP] blob sn#754078 filedate 1984-05-12 generic text, type T, neo UTF8
@Part[XERROR, Root = "CLM.MSS"]
@Comment{Chapter of Common Lisp Manual.  Copyright 1984 Guy L. Steele Jr.⎇

@mychapter [Errors]
@label[XERROR]

Errors may be signalled for a variety of reasons.
Many built-in @clisp functions may signal an error when given incorrect
arguments.  Other functions, described in this chapter,
may be called by user programs for the purpose of signalling
an error.

When an error is signalled, it is
handled in an implementation-dependent way.  It is expected
that each implementation of @clisp will provide an interactive debugger that
prints the error message along with suitable contextual information
such as which function detected the error.  The user may interact with
the debugger to examine or modify the state of the program in various
ways, including abandoning the current computation (``aborting to top
level'') and continuing from the error.  What ``continuing'' means
depends on how the error is signalled; the details of this are specified below
for each error signalling function.

An implementation may also choose to provide means (such as the
@f[errset] special form in @maclisp) for a program to trap
all errors and prevent the debugger from stepping in for
certain errors.

@Rationale{Error-handling of adequate
flexibility and power for all systems written in @clisp appears to
require a complex error classification system.
Experience with several error-handling systems
in such dialects as @maclisp and @lmlisp indicates that
further experimentation is needed in this area;
it is too early to define a standard error-handling mechanism.
Therefore @clisp provides standard ways to @i[signal] errors,
but no standard ways to @i[handle] errors.
Of course a
complete @xlisp system requires error-handling mechanisms, but many useful
portable programs do not require them.  It is expected that a future
revision of @clisp will address the problem of portable error-handling
mechanisms.⎇

@incompatibility{What is here called ``continuing,''
@lmlisp calls ``proceeding'' from an error.⎇

@section[General Error-Signalling Functions]

The functions in this section provide various mechanisms
for signalling warnings, breaks, continuable errors, and fatal errors.

In each case, the caller specifies an error message (a string) that may be
processed (and perhaps displayed to the user) by the error-handling
mechanism.  All messages are
constructed by applying the function
@Funref[format] to the quantities @nil, @i[format-string],
and all the @i[args] to produce a string.

An error message string should not contain a newline character
at either the beginning or end, and should not contain any sort of
herald indicating that it is an error.  The system will take care of
these according to whatever its preferred style may be.  

Conventionally,
error messages are complete English sentences ending with a period.
Newlines in the middle of long messages are acceptable.  There
should be no indentation after a newline in the middle of an
error message.  The error message need not mention the name of the function
that signals the error; it is assumed that the debugger will make this
information available.

@implementation{If the debugger in a particular implementation
displays error messages indented from the prevailing left margin
(for example, indented by seven spaces because
they are prefixed by the seven-character herald ``@f[Error: ]''),
then the debugger should take care of inserting
the appropriate indentation into a multi-line error message.
Similarly, a debugger that prefixes error messages with semicolons
so that they appear to be comments
should take care of inserting a semicolon at the beginning of each
line in a multi-line error message.  These rules are suggested
because, even within a single
implementation, there may be more than one program that presents error
messages to the user, and they may use different styles of
presentation.  The caller
of @f[error] cannot anticipate all such possible styles,
and so it is incumbent upon the presenter of the message
to make any necessary adjustments.⎇

@clisp does not specify the manner in which error messages and
other messages are displayed.  For the purposes of exposition,
a fairly simple style of textual presentation will be used in the
examples in this chapter.  The character @f[>] is used
to represent the command prompt symbol for a debugger.

@defun[Fun {error⎇, Args {@i[format-string] @rest @i[args]⎇]

This function signals a fatal error.  It is impossible to continue
from this kind of 
error; thus @f[error] will never return to its caller.

The debugger printout in the following example is typical of what
an implementation might print when @f[error] is called.
Suppose that the symbol @f[emergnecy-shutdown] has no property
named @f[command] (all too likely, as it is probably a typographical
error for @f[emergency-shutdown]).
@lisp
(defun command-dispatch (cmd)
  (let ((fn (get cmd 'command)))
    (if (not (null fn))
	(funcall fn))
	(error "The command @tilde@;S is unrecognized." cmd))))

(command-dispatch 'emergnecy-shutdown)
Error: The command EMERGNECY-SHUTDOWN is unrecognized.
Error signalled by function COMMAND-DISPATCH.
> 
@endlisp

@incompatibility{@lmlisp calls this function @f[ferror].
@maclisp has a function named @f[error] that takes
different arguments and can signal either a fatal or a continuable error.⎇
@enddefun

@defun[Fun {cerror⎇, Args {@i[continue-format-string] @i[error-format-string] @rest @i[args]⎇]
@f[cerror] is used to signal continuable errors.  Like @f[error], it
signals an error and enters the debugger.  However, @f[cerror] allows
the program to be continued from the debugger after resolving the
error.  

If the program is continued after encountering the error, @f[cerror]
returns @false.  The code that follows the call to @f[cerror] will
then be executed.   This code should correct the problem, perhaps by
accepting a new value from the user if a variable was invalid.

If the code that corrects the problem interacts with the program's 
use and might possibly be misled,
it should make sure the error has really been corrected before
continuing.  One way to do this is to put the call to @f[cerror] and
the correction code in a loop, checking each time to see if the error
has been corrected before terminating the loop.

The @i[continue-format-string] argument, like the @i[error-format-string]
argument, is given as a control string to @Funref[format] along with
the @i[args] to construct a message string.
The error message string is used in the same way that @f[error] uses it.
The continue message string should
describe the effect of continuing.  The intent is that this
message can be displayed as an aid to the user in deciding whether and
how to continue.  For example, it might
be used by an interactive debugger as part of the documentation of its
``continue'' command.  

The content of the continue message should adhere to the rules
of style for errors messages.  It should not include
any statement of how the ``continue'' command is given, since this may be
different for each debugger.  (It is up to the debugger to supply this
information according to its own particular style of presentation and user
interaction.)

Here is an example where the caller of @f[cerror], if continued,
fixes the problem without any further user interaction:
@lisp
(let ((nvals (list-length vals)))
  (unless (= nvals 3)
    (cond ((< nvals 3)
	   (cerror "Assume missing values are zero."
		   "Too few values in @tilde@;S;@tilde@;%@tilde@;
		    three are required, @tilde@;
		    but @tilde@;R @tilde@;:@lbracket@;were@tilde@;;was@tilde@;@rbracket@; supplied."
		   nvals (= nvals 1))
	   (setq vals (append vals (subseq '(0 0 0) nvals 3))))
	  (t (cerror "Ignore all values after the first three."
		     "Too many values in @tilde@;S;@tilde@;%@tilde@;
		      three are required, @tilde@;
		      but @tilde@;R were supplied."
		      nvals)
	     (setq vals (subseq vals 0 3))))))
@endlisp
If @f[vals] were the list @f[(-47)], the interaction might look
like this:
@lisp
Error: Too few values in (-47);
       three are required, but one was supplied.
Error signalled by function EXAMPLE.
If continued: Assume missing values are zero.
>
@endlisp
In this example, a loop is used to ensure that a test is satisfied.
(This example could be written more succinctly using @Macref[assert]
or @f[check-type], which indeed supply such loops.)
@lisp
(do ()
    ((known-wordp word) word)
  (cerror "You will be prompted for a replacement word."
	  "@tilde@;S is an unknown word (possibly misspelled)."
	  word)
  (format *query-io* "@tilde@;&New word: ")
  (setq word (read *query-io*)))
@endlisp

In complex cases where the @i[error-format-string]
uses some of the @i[args] and the
@i[continue-format-string] uses others, it may be necessary to use the
@f[format] directives @f[@tilde@;*] and @f[@tilde@;@@*]
to skip over unwanted arguments in one or both of the
format control strings.

@incompatibility{The @lmlisp function @f[fsignal] is similar to this, but
returns @kwd[no-action]
rather than @false, and fails to distinguish between the error message
and the continue message.⎇
@enddefun

@defun[Fun {warn⎇, Args {@i[format-string] @rest @i[args]⎇]
@f[warn] prints an error message, but normally
doesn't go into the debugger.  (However, this may be controlled
by the variable @varref[break-on-warnings].)
@f[warn] returns @false.

This function would be just the same as
@Funref[format] with the output directed 
to the stream in @varref[error-output], except that @f[warn]
may perform various implementation-dependent formatting and
other actions.  For example, an implementation of @f[warn] should take
care of advancing to a fresh line before and after the error message
and perhaps supplying the name of the function that called @f[warn].

@incompatibility{The @lmlisp function @f[compiler:warn] is an
approximate equivalent to this.⎇
@enddefun

@defvar[Var {break-on-warnings⎇]

If @var[break-on-warnings] is not @false, then the function
@f[warn] behaves like
@f[break].  It prints its message and then goes to the debugger or break
loop.  Continuing causes @f[warn] to return @false.  This flag is intended
primarily for use when the user is debugging programs that issue warnings;
in ``production'' use, the value of @var[break-on-warnings] should be @false.
@enddefvar

@defun[Fun {break⎇, Args {@optional @i[format-string] @rest @i[args]⎇]
@f[break] prints the message and goes directly into the debugger,
without allowing 
any possibility of interception by programmed error-handling facilities.
(Right now, there aren't any error-handling facilities defined in @clisp,
but there might be in particular implementations, and there will be some
defined by @clisp in the future.)
When continued, @f[break] returns @false.  It is permissible to
call @f[break] with no arguments; a suitable default message will be provided.

@f[break] is presumed to be used as a way of inserting temporary debugging
``breakpoints'' in a program, not as a way of signalling errors;
it is expected that
continuing from a @f[break] will not trigger any unusual recovery action.
For this reason, @f[break] does not
take the additional @f[format] control-string argument that @f[cerror]
takes.  This and the lack of any possibility of interception by programmed
error-handling are the only program-visible differences between @f[break]
and @Funref[cerror].
The interactive debugger may choose to display them
differently; for instance, a @f[cerror] message might be prefixed with
the herald
``@f[Error: ]'' and a @f[break] message with
``@f[Break: ]''.  This depends on
the user-interface style of the particular implementation.  A particular
implementation may choose, according to its own style and needs,
when @f[break] is called to go
into a debugger different from the one used for handling errors.
For example, it might go into an ordinary read-eval-print loop identical to
the top-level one except for the provision of a ``continue'' command that
causes @f[break] to return @false.

@Incompatibility{In @maclisp, @f[break] is a special form (@c[FEXPR])
that takes two optional arguments.  The first is a symbol (it would be a
string if @Maclisp had strings), which is not evaluated.  The second is
evaluated to produce a truth value specifying whether @f[break] should
break (true) or return immediately (false).  In @clisp one makes a call
to @f[break] conditional by putting it inside a conditional form such as
@Macref[when] or @Macref[unless].⎇
@enddefun

@section[Specialized Error-Signalling Forms and Macros]

These facilities are designed to make it convenient for the user
to insert error checks into his code.

@Defmac[Fun {check-type⎇, Args {@i[place] @i[typespec] @optional @i[string]⎇]
@f[check-type] signals an error if the contents of @i[place] are not
of the desired type.
If the user continues from this error, he will be asked for a new value;
@f[check-type] will store the new value in @i[place] and start over, 
checking the type of the new value and signalling
another error if it is still not of the desired type.  Subforms of
@i[place] may be evaluated multiple times because of the implicit
loop generated.  @f[check-type] returns @false.

The @i[place] must be a generalized variable reference acceptable to
@Macref[setf].
The @i[typespec] must be a type specifier; it is not evaluated.
The @i[string] should be an English description of the type, starting with
an indefinite article (``a'' or ``an''); it is evaluated.
If @i[string] is
not supplied, it is computed automatically from @i[typespec].
(The optional @i[string] argument is allowed because some applications
of @f[check-type] may require a more specific description of what is
wanted than can be generated automatically from the type specifier.)

The error message will mention @f[place], its contents, and the desired type.
@Implementation{An implementation may choose to
generate a somewhat differently worded
error message if it recognizes that @i[place] is of a particular
form, such as one of the arguments to
the function that called @f[check-type].⎇

Examples:
@lisp
(setq aardvarks '(sam harry fred))
(check-type aardvarks (vector integer))
Error: The value of AARDVARKS, (SAM HARRY FRED),
       is not a vector of integers.

(setq naards 'foo)
(check-type naards (integer 0 *) "a positive integer")
Error: The value of NAARDS, FOO, is not a positive integer.
@endlisp

@Incompatibility{In @lmlisp the equivalent facility
is called @f[check-arg-type].⎇
@enddefmac


@defmac[fun {assert⎇, args {@i[test-form] @mopt"(@mstar<@i[place]>) @mopt<@i[string] @mstar'@i[arg]'>"⎇]
@f[assert] signals an error if the value of @i[test-form] is @false.
Continuing 
from this error will allow the user to alter the values of some
variables, and @f[assert] will then start over, evaluating 
@i[test-form] again.  @f[assert] returns @false.

@i[test-form] is any form.  Each @i[place] (there may be any number of
them, or none) must be a generalized-variable reference acceptable to
@Macref[setf].  These should be variables on which @i[test-form] depends,
whose values may sensibly be changed by the user in attempting to correct
the error.  Subforms of each @i[place] are only evaluated if an error is
signalled, and may be re-evaluated if the error is re-signalled (after
continuing without actually fixing the problem).

The @i[string] is an
error message string, and the @i[args] are additional arguments; they are
evaluated only if an error is signalled, and re-evaluated if the error is
signalled again.
The function @Funref[format] is applied in the usual way to
@i[string] and @i[args] to produce
the actual error message.  If @i[string] is omitted (and therefore also
the @i[args]), a default error message is used.

@Implementation{The debugger need not include
the @i[test-form] in the error message,
and the @i[places] should not be included in the message, but they
should be made available for the user's perusal.
If the user gives the ``continue'' command, he should be
presented with the opportunity to alter the values of any or all of the
references.  The details of this depend on the
implementation's style of user interface, of course.⎇

Examples:
@lisp
(assert (valve-closed-p v1))

(assert (valve-closed-p v1) () "Live steam is escaping!")

(assert (valve-closed-p v1)
        ((valve-manual-control v1))
	"Live steam is escaping!")

;; Note here that the user is invited to change BASE, 
;; but not the bounds MINBASE and MAXBASE.
(assert (<= minbase base maxbase)
	(base)
        "Base @tilde@;D is not in the range [@tilde@;D, @tilde@;D]"
	base minbase maxbase)

;; Note here that it is probably not desirable to include the
;; entire contents of the two matrices in the error message.
;; It is reasonable to assume that the debugger will give
;; the user access to the values of the places A and B.
(assert (= (array-dimension a 1) 
	   (array-dimension b 0))
	(a b)
	"Cannot multiply a @tilde@;D-by-@tilde@;D matrix @tilde@;
	 and a @tilde@;D-by-@tilde@;D matrix."
	(array-dimension a 0)
	(array-dimension a 1)
	(array-dimension b 0)
	(array-dimension b 1))
@endlisp
@enddefmac

@section[Special Forms for Exhaustive Case Analysis]

The syntax for @f[etypecase] and @f[ctypecase] is the same as for
@Macref[typecase], except that no @f[otherwise] clause is permitted.
Similarly, the syntax for @f[ecase] and @f[ccase] is the same as for
@Macref[case] except for the @f[otherwise] clause.

@f[etypecase] and @f[ecase] are similar to @f[typecase] and @f[case],
respectively, but signal a non-continuable error rather than returning
@false if no clause is selected.

@f[ctypecase] and @f[ccase] are also similar to @f[typecase] and @f[case],
but signal a continuable error if no clause is selected.

@Defmac[Fun {etypecase⎇, Args {@i[keyform] @Mstar<(@i[type] @mstar'@i[form]')>⎇]
This control construct is similar to @Macref[typecase],
but no explicit @f[otherwise] or @f[t] clause is permitted.
If no clause is satisfied, @f[etypecase] signals an error with
a message constructed from the clauses.  It is not permissible to
continue from this error.  To supply his own error message, the user
should use @f[typecase] with an @f[otherwise] clause containing a call
to @f[error].  The name of this function stands for ``exhaustive
type case'' or ``error-checking type case.''
For example:
@lisp
(setq x 1/3)
(etypecase x
  (integer x)
  (symbol (symbol-value x)))
Error: The value of X, 1/3, is neither
       an integer nor a symbol.
>
@endlisp
@enddefmac

@Defmac[Fun {ctypecase⎇, Args {@i[keyplace] @Mstar<(@i[type] @mstar'@i[form]')>⎇]
This control construct is similar to @Macref[typecase],
but no explicit @f[otherwise] or @f[t] clause is permitted.
The @i[keyplace] must be a generalized variable reference
acceptable to @f[setf].  If no clause is satisfied, @f[ctypecase] signals an
error with a message constructed from the clauses.  Continuing from this
error causes @f[ctypecase] to accept a new value from the user, store
it into @i[keyplace], and start over, making the type tests again.
Subforms of @i[keyplace] may be evaluated multiple times.  The name
of this function stands for ``continuable exhaustive type case.''
@enddefmac

@Defmac[Fun {ecase⎇, Args {@i[keyform] @Mstar<(@Mgroup"(@Mstar'@i[key]') @Mor @i[key]" @Mstar'@i[form]')>⎇]
This control construct is similar to @Macref[case],
but no explicit @f[otherwise] or @f[t] clause is permitted.
If no clause is satisfied, @f[ecase] signals an error with a
message constructed from the clauses.  It is not permissible to continue
from this error.  To supply an error message, the user should use
@f[case] with an @f[otherwise] clause containing a call to @f[error].
The name of this function stands for ``exhaustive case'' or
``error-checking case.'' 
For example:
@lisp
(setq x 1/3)	
(ecase x
  (alpha (foo))
  (omega (bar))
  ((zeta phi) (baz)))
Error: The value of X, 1/3, is not
       ALPHA, OMEGA, ZETA, or PHI.
@endlisp
@enddefmac

@Defmac[Fun {ccase⎇, Args {@i[keyplace] @Mstar<(@Mgroup"(@Mstar'@i[key]') @Mor @i[key]" @Mstar'@i[form]')>⎇]
This control construct is similar to @Macref[case],
but no explicit @f[otherwise] or @f[t] clause is permitted.
The @i[keyplace] must be a generalized variable reference
acceptable to @f[setf].  If no clause is satisfied, @f[ccase] signals an error
with a message constructed from the clauses.  Continuing from this error
causes @f[ccase] to accept a new value from the user, store it into
@i[keyplace], and start over, making the clause tests again.  Subforms of
@i[keyplace] may be evaluated multiple times.  The name of this function
stands for ``continuable exhaustive case.''
@enddefmac

@Rationale{The special forms
@f[etypecase], @f[ctypecase], @f[ecase], and @f[ccase]
are included in @clisp, even though a user
could write them himself using the other standard facilities provided,
because it is likely that many users will want these.
@clisp therefore provides
a standard consistent set rather than allowing
a variety of incompatible dialects to develop.

In addition, experience has shown that
some @xlisp programmers are too lazy to put an appropriate
@f[otherwise] clause into every @Macref[case] statement to
check for cases they
didn't anticipate, even if they would agree that it will probably 
hurt them later.  If an @f[otherwise] clause can be included
very easily by adding one character to the name of the construct,
it is perhaps more likely that programmers will take the trouble to do it. 

The @f[e] versions do nothing more than supply
automatically generated @f[otherwise] clauses, but correct
implementation of the @f[c] versions
requires some care.  It is therefore especially
important that the @f[c] versions be provided
by the system so users don't have to puzzle them out on
their own.  Individual implementations may be able to do a better job
of supporting these special forms,
using their own idiosyncratic facilities, than can be done
using the error-signalling facilities defined by @clisp.⎇